package org.aeon.gamechatnest.configuration.thread;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aeon.gamechatnest.socket.ChatMessageClient;
import org.aeon.gamechatnest.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.Deque;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author MissingAeon
 * @date 2024/5/20 10:56
 * @description 消息发送线程
 */
@Slf4j
@Component("messageSendHandler")
@Scope("prototype")
public class MessageSendHandler implements Runnable {
    private final CopyOnWriteArrayList<ChatMessageClient> messageCheckQueue = new CopyOnWriteArrayList<>();

    @Lazy
    @Autowired
    private ApplicationContext context;

    // 下一个消息发送线程 一个循环链表结构
    private MessageSendHandler messageSendThread;

    @Getter
    private boolean running = false;

    private static void sleep(long millis) {
        try {
            // TODO 优化休眠逻辑
            Thread.sleep(millis);
        } catch (InterruptedException ignored) {
        }
    }

    @Override
    public void run() {
        running = true;
        while (running) {
            messageCheckQueue.forEach(client -> {
                Deque<Object> responseQueue = client.getResponseQueue();
                if (responseQueue.isEmpty()) return;
                while (true) {
                    Object message = client.getResponseQueue().pollLast();
                    if (Objects.isNull(message)) break;
                    messageSend(client, message);
                }
            });
            sleep(100);
            // TODO 线程意外停止重新启动
        }
        log.debug("信息发送线程log:>>>{}线程结束...", Thread.currentThread().getName());
    }

    /**
     * 消息发送
     *
     * @param client
     * @param message
     */
    private void messageSend(ChatMessageClient client, Object message) {
        try {
            client.getSession().getAsyncRemote().sendText(JsonUtil.obj2String(message));
        } catch (Exception e) {
            log.debug("信息发送线程log:>>>发送消息失败...,{}", e.getMessage());
            resend(client, message, 1);
        }
    }

    /**
     * 重新发送消息
     *
     * @param client
     * @param message
     * @param retryCount
     */
    private void resend(ChatMessageClient client, Object message, int retryCount) {
        log.debug("信息发送线程log:>>>重新发送消息...");
        try {
            client.getSession().getAsyncRemote().sendText(JsonUtil.obj2String(message));
        } catch (IllegalStateException e) {
            log.debug("信息发送线程log:>>>发送消息失败...");
            if (client.getSession().isOpen()) {
                log.debug("信息发送线程log:>>>重新发送消息...");
                if (retryCount < 3) {
                    sleep(5);
                    resend(client, message, retryCount + 1);
                } else {
                    log.error("信息发送线程log:>>>用户:{},重试次数过多,发送消息失败...",
                            client.getSession().getRequestURI().toString());
                }
            } else {
                // 用户已下线
                messageCheckQueue.remove(client);
                // TODO 丢失消息重新进入同步库
                log.debug("信息发送线程log:>>>丢失消息重新进入同步库...");
            }
        }
    }

    /**
     * 将客户端绑定到信息发送线程
     *
     * @param client
     */
    public void bindQueue(ChatMessageClient client) {
        if (messageCheckQueue.size() > 100) {
            log.debug("信息发送线程log:>>>线程发送消息数量过多，需要新建线程...");
            // 扩展线程链表
            if (this.messageSendThread == context.getBean("messageSendThread", MessageSendHandler.class)) {
                // 判断自己是不是尾线程，不是尾线程将多余的绑定给下一个线程，如果自己就是尾线程就创建线程
                // 获取原型,交换始终让最后一个线程的下一个指向头
                MessageSendHandler messageSendHandler = context.getBean("messageSendHandler", MessageSendHandler.class);
                messageSendHandler.messageSendThread = messageSendThread;
                messageSendThread = messageSendHandler;

                if (!messageSendThread.isRunning()) {
                    // 启动
                    context.getBean(ThreadPoolExecutor.class).execute(messageSendThread);
                }
            }
            // 将多余的绑定给下一个线程
            messageSendThread.bindQueue(client);
        } else messageCheckQueue.add(client);
    }

    /**
     * 解绑
     *
     * @param client
     */
    public void unbindQueue(ChatMessageClient client) {
        messageCheckQueue.remove(client);
        if (messageCheckQueue.isEmpty()) {
            // 判断自己是不是主线程
            if (this != context.getBean("messageSendThread", MessageSendHandler.class)) {
                log.debug("信息发送线程log:>>>出现了空的消息发送线程，销毁多余的线程...");
                // 开始销毁
                cleanUpThreads(this);
            }
        }
    }

    /**
     * 在链表中清除自己
     *
     * @param messageSendThread
     */
    private void cleanUpThreads(MessageSendHandler messageSendThread) {
        // 循环到目标前一个线程
        if (this.messageSendThread == messageSendThread) {
            // 设置为停止运行
            messageSendThread.running = false;
            // 将该线程排除
            this.messageSendThread = messageSendThread.messageSendThread;
        } else {
            this.messageSendThread.cleanUpThreads(messageSendThread);
        }
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        running = false;
        return super.clone();
    }
}
